package charpter01_basic.lession04_wait_notify_notifyall;

import org.junit.Test;

/**
 * 为什么 wait方法必须在 synchronized保护的同步代码中使用？
 * 为什么 wait/notify/notifyAll 被定义在 Object 类中，而 sleep 定义在 Thread 类中？
 * wait/notify 和 sleep 方法的异同？
 */
public class WaitNotifyNotifyAll {
    /**
     * 以下英文来自源码，在使用 wait 方法时，必须把 wait 方法写在 synchronized
     * 保护的 while 代码块中，并始终判断执行条件是否满足，如果满足就往下继续执行，
     * 如果不满足就执行 wait 方法，而在执行 wait 方法之前，必须先持有对象的 monitor 锁，也就是通常所说的synchronized锁
     * As in the one argument version, interrupts and spurious wakeups are possible, and this method should always be used in a loop:
     *       synchronized (obj) {
     *           while (<condition does not hold>)
     *               obj.wait();
     *           ... // Perform action appropriate to condition
     *       }
     * This method should only be called by a thread that is the owner of this object's monitor.
     * See the notify method for a description of the ways in which a thread can become the owner of a monitor.
     */
    @Test
    public void waitTest1(){
        BlockingQueueWithoutSynchronized blockingQueueWithoutSynchronized = new BlockingQueueWithoutSynchronized();
        executeProduceAndConsum(blockingQueueWithoutSynchronized);
    }

    @Test
    public void waitTest2(){
        BlockingQueue blockingQueue = new BlockingQueue();
        executeProduceAndConsum(blockingQueue);
    }

    private void executeProduceAndConsum(MyBlockingQueue blockingQueue) {
        new Thread(() -> {
            while (true){
                blockingQueue.give("1");
            }
        }).start();
        new Thread (()->{
            while (true){
                try {
                    System.out.println(blockingQueue.take());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
}
